package com.beiji.lib.pen.ui.renderer

import android.graphics.Canvas
import android.graphics.Matrix
import android.graphics.Paint
import android.graphics.Path
import com.beiji.lib.pen.constants.PaletteColor
import com.beiji.lib.pen.model.DotUnit
import com.beiji.lib.pen.model.PenStroke
import com.tqltech.tqlpencomm.bean.Dot

/**
 * TQL PenNote渲染器
 * Created by X on 2018/6/21.
 */
class TQLRenderer : Renderer() {

    private var gPIndex = -1
    private var g_x0: Float = 0f
    private var g_x1: Float = 0f
    private var g_x2: Float = 0f
    private var g_x3: Float = 0f
    private var g_y0: Float = 0f
    private var g_y1: Float = 0f
    private var g_y2: Float = 0f
    private var g_y3: Float = 0f
    private var g_p0: Float = 0f
    private var g_p1: Float = 0f
    private var g_p2: Float = 0f
    private var g_p3: Float = 0f
    private var g_vx01: Float = 0f
    private var g_vy01: Float = 0f
    private var g_n_x0: Float = 0f
    private var g_n_y0: Float = 0f
    private var g_vx21: Float = 0f
    private var g_vy21: Float = 0f
    private var g_norm: Float = 0f
    private var g_n_x2: Float = 0f
    private var g_n_y2: Float = 0f
    private var width1: Int = 0
    private var path: Path = Path()
    private var defaultPaint: Paint = Paint()
    private var penWidth = 5

    init {
        defaultPaint.apply {
            isAntiAlias = true
//            strokeWidth = 3f 当style为Fill类型时，strokeWidth无效，因为strokeWidth是描边宽度
            color = PaletteColor.COLOR_0.toColor()
            style = Paint.Style.FILL
            strokeJoin = Paint.Join.ROUND
            strokeCap = Paint.Cap.ROUND
            strokeMiter = 0.3f
        }
    }

    override fun reset() {
    }


    override fun draw(canvas: Canvas, stroke: PenStroke, dotMatrix: Matrix, paint: Paint?) {
        val drawPaint = defaultPaint
        for (i in stroke.list.indices) {
            val point = StrokeTransformHelper.transformPenPoint(stroke.list[i], dotMatrix)
            if (i == 0) {
                gPIndex = 0
                drawSubFountainPen(canvas, 1f, 0f, 0f, penWidth, point.x.toFloat(), point.y.toFloat(), point.f, drawPaint)
            } else {
                gPIndex++
                drawSubFountainPen(canvas, 1f, 0f, 0f, penWidth, point.x.toFloat(), point.y.toFloat(), point.f, drawPaint)
            }
        }
        gPIndex = -1
    }

    override fun draw(canvas: Canvas, dot: DotUnit, paint: Paint?) {
        val drawPaint = paint ?: defaultPaint
        drawPaint.style = Paint.Style.FILL
//        val drawPaint = defaultPaint
        if (dot.type == Dot.DotType.PEN_DOWN) {
            gPIndex = 0
            drawSubFountainPen(canvas, 1f, 0f, 0f, penWidth, dot.x.toFloat(), dot.y.toFloat(), dot.force, drawPaint)
        } else if (dot.type == Dot.DotType.PEN_MOVE) {
            gPIndex++
            drawSubFountainPen(canvas, 1f, 0f, 0f, penWidth, dot.x.toFloat(), dot.y.toFloat(), dot.force, drawPaint)
        } else if (dot.type == Dot.DotType.PEN_UP) {
            gPIndex++
            drawSubFountainPen(canvas, 1f, 0f, 0f, penWidth, dot.x.toFloat(), dot.y.toFloat(), dot.force, drawPaint)
            gPIndex = -1
        }

    }

    private fun drawSubFountainPen(canvas: Canvas?, scale: Float, offsetX: Float, offsetY: Float, penWidth: Int, x: Float, y: Float, force: Float, paint: Paint) {
        //Assert.assertTrue( mN >= 2 );

        //DV.setLayerType(View.LAYER_TYPE_HARDWARE, null);
//        val scaled_pen_thickness = getScaledPenThickness(mPenThickness.toFloat(), scale)
        //Log.i(TAG, "drawSubFountainPen--");

        // the first actual point is treated as a midpoint
        if (gPIndex == 0) {
            g_x0 = x * scale + offsetX + 0.1f
            g_y0 = y * scale + offsetY
            g_p0 = Math.max(1f, penWidth.toFloat() * scale * force / 1023)
            //g_p0 = 5;
            width1 = g_p0.toInt()
            canvas?.drawCircle(g_x0, g_y0, 0.5.toFloat(), paint)
            return
        }

        if (gPIndex == 1) {
            g_x1 = x * scale + offsetX + 0.1f
            g_y1 = y * scale + offsetY
            g_p1 = Math.max(1f, penWidth.toFloat() * scale * force / 1023)
            width1 = g_p1.toInt()
            g_vx01 = g_x1 - g_x0
            g_vy01 = g_y1 - g_y0
            // instead of dividing tangent/norm by two, we multiply norm by 2
            g_norm = Math.sqrt((g_vx01 * g_vx01 + g_vy01 * g_vy01 + 0.0001f).toDouble()).toFloat() * 2f
            g_vx01 = g_vx01 / g_norm * g_p0
            g_vy01 = g_vy01 / g_norm * g_p0
            g_n_x0 = g_vy01
            g_n_y0 = -g_vx01
            return
        }

        if (gPIndex > 1 && gPIndex < 10000) {
            // (x0,y0) and (x2,y2) are midpoints, (x1,y1) and (x3,y3) are actual
            // points
            g_x3 = x * scale + offsetX + 0.1f
            g_y3 = y * scale + offsetY
            g_p3 = Math.max(1f, penWidth.toFloat() * scale * force / 1023)
            width1 = g_p3.toInt()

            g_x2 = (g_x1 + g_x3) / 2f
            g_y2 = (g_y1 + g_y3) / 2f
            g_p2 = (g_p1 + g_p3) / 2f
            g_vx21 = g_x1 - g_x2
            g_vy21 = g_y1 - g_y2
            g_norm = Math.sqrt((g_vx21 * g_vx21 + g_vy21 * g_vy21 + 0.0001f).toDouble()).toFloat() * 2f
            g_vx21 = g_vx21 / g_norm * g_p2
            g_vy21 = g_vy21 / g_norm * g_p2
            g_n_x2 = -g_vy21
            g_n_y2 = g_vx21


            path.rewind()
            path.moveTo(g_x0 + g_n_x0, g_y0 + g_n_y0)
            // The + boundary of the penStroke
            path.cubicTo(g_x1 + g_n_x0, g_y1 + g_n_y0, g_x1 + g_n_x2, g_y1 + g_n_y2, g_x2 + g_n_x2, g_y2 + g_n_y2)
            // round out the cap
            path.cubicTo(g_x2 + g_n_x2 - g_vx21, g_y2 + g_n_y2 - g_vy21, g_x2 - g_n_x2 - g_vx21, g_y2 - g_n_y2 - g_vy21, g_x2 - g_n_x2, g_y2 - g_n_y2)
            // THe - boundary of the penStroke
            path.cubicTo(g_x1 - g_n_x2, g_y1 - g_n_y2, g_x1 - g_n_x0, g_y1 - g_n_y0, g_x0 - g_n_x0, g_y0 - g_n_y0)
            // round out the other cap
            path.cubicTo(g_x0 - g_n_x0 - g_vx01, g_y0 - g_n_y0 - g_vy01, g_x0 + g_n_x0 - g_vx01, g_y0 + g_n_y0 - g_vy01, g_x0 + g_n_x0, g_y0 + g_n_y0)
            canvas?.drawPath(path, paint)

            g_x0 = g_x2
            g_y0 = g_y2
            g_p0 = g_p2
            g_x1 = g_x3
            g_y1 = g_y3
            g_p1 = g_p3
            g_vx01 = -g_vx21
            g_vy01 = -g_vy21
            g_n_x0 = g_n_x2
            g_n_y0 = g_n_y2
            return
        }
        if (gPIndex >= 10000) {//Last Point
            g_x2 = x * scale + offsetX + 0.1f
            g_y2 = y * scale + offsetY
            g_p2 = Math.max(1f, penWidth.toFloat() * scale * force/ 1023)
            width1 = g_p2.toInt()

            g_vx21 = g_x1 - g_x2
            g_vy21 = g_y1 - g_y2
            g_norm = Math.sqrt((g_vx21 * g_vx21 + g_vy21 * g_vy21 + 0.0001f).toDouble()).toFloat() * 2f
            g_vx21 = g_vx21 / g_norm * g_p2
            g_vy21 = g_vy21 / g_norm * g_p2
            g_n_x2 = -g_vy21
            g_n_y2 = g_vx21

            path.rewind()
            path.moveTo(g_x0 + g_n_x0, g_y0 + g_n_y0)
            path.cubicTo(g_x1 + g_n_x0, g_y1 + g_n_y0, g_x1 + g_n_x2, g_y1 + g_n_y2, g_x2 + g_n_x2, g_y2 + g_n_y2)
            path.cubicTo(g_x2 + g_n_x2 - g_vx21, g_y2 + g_n_y2 - g_vy21, g_x2 - g_n_x2 - g_vx21, g_y2 - g_n_y2 - g_vy21, g_x2 - g_n_x2, g_y2 - g_n_y2)
            path.cubicTo(g_x1 - g_n_x2, g_y1 - g_n_y2, g_x1 - g_n_x0, g_y1 - g_n_y0, g_x0 - g_n_x0, g_y0 - g_n_y0)
            path.cubicTo(g_x0 - g_n_x0 - g_vx01, g_y0 - g_n_y0 - g_vy01, g_x0 + g_n_x0 - g_vx01, g_y0 + g_n_y0 - g_vy01, g_x0 + g_n_x0, g_y0 + g_n_y0)
            canvas?.drawPath(path, paint)
            return
        }
    }
}